<?php
include "../base.php";
include "../server/ToolServer.php";
include "../server/HredisServer.php";
include "../server/SearchServer.php";

class index extends base
{
    public $toolServer;
    public $redisServer;
    public $searchServer;
    public $forbidMsg = 'pass';
    public $forbidType = 0;
    public $address = '';
    public $now = 0;
    public $blackOaidRedisTable = "OaidBlacklist"; //oaid黑名单
    public $blackIpRedisTable = "IpBlacklist"; //oaid黑名单
    public $placeKey = "JINGYUE_PLACES"; //鲸跃广告位点击率KEY
    public $hapLogKey = 'JINGYUE_HAP_LOG'; // hap请求日志redis Key
    public $whiteOaids = ['fdfdfd7d-b76b-2ac7-ace7-f7b7f3dda510', 'ea9e10e0a08ebc25', 'fdfdfd7d-b76b-2ac7-ace7', '00000000-0000-0000-0000-000000000000']; // 白名单oaid

    public $whiteIps = []; // 白名单oaid
    // 不进行验证的oaid
    public $passOaid = [];
    // 阈值
    public $limitValue = 15;
    // 投放链接数据
    public $linkRow = [];
    // 广告规则以及屏蔽规则屏蔽规则数据
    public $ruleRow = [];


    public function __construct()
    {
        $this->toolServer = new ToolServer();
        $this->redisServer = new HredisServer();
        $this->searchServer = new SearchServer();
        $this->now = time();

    }

    public function exc()
    {
        $tool = $this->toolServer;
        try {
            $request = $_REQUEST;
            if (empty($request['hap'])) {
                $request = json_decode(file_get_contents("php://input"), true);
            }
            $client['signature'] = $request['signature'] ?? '';
            $client['ip'] = $tool->getIp();
            $client['oaid'] = $request['oaid'] ?? '';
            $client['ts'] = !empty($request['ts']) ? (int)$request['ts'] : time();
            $client['fromPkg'] = $request['fromPkg'] ?? '';
            $client['producer'] = $request['producer'] ?? '';
            $hap = $request['hap'] ?? '';
            if (strpos($hap, 'huawei/') !== false) {
                $hap = str_replace('huawei/', 'huawei', $hap);
            }
            if (strpos($hap, 'huawei%2F') !== false) {
                $hap = str_replace('huawei%2F', 'huawei', $hap);
            }
            $res = $this->check($client, $hap);
            die();

        } catch (Exception $e) {
            $tool->error('未知错误，稍后重试');
        }
    }

    /**
     * 检验
     * @param $client
     * @param $hap
     * @return void
     */
    public function check($client, $hap)
    {
        $tool = $this->toolServer;
        if (empty($client['producer'])) {
            $tool->error('producer is must');
        }
        if (empty($hap)) {
            $tool->error('invalid hap');
        }
        $hapArr = $this->toolServer->splitParam($hap);
        $channo = $hapArr['channo'] ?? '';
        $chanurlno = $hapArr['chanurlno'] ?? '';
        $version = $hapArr['v'] ?? 0;
//        $ip = $this->toolServer->getIp();
        $ip = '58.23.250.138';
        $rowData = [
            'ip' => $ip,
            'oaid' => $client['oaid'],
            'ts' => $client['ts'],
            'fromPkg' => $client['fromPkg'],
            'producer' => $client['producer'],
            'channo' => $channo,
            'chanurlno' => $chanurlno,
            'version' => $version,
            'ymd'=>date("Ymd",$this->now),
            'hap' => $hap,
            'create_at' => $this->now,
            'hap_ts' => $hapArr['ts'] ?? 0,
            'hap_oaid' => $hapArr['hapoaid'] ?? '',
            'hap_ip' => $hapArr['hapip'] ?? '',
            'is_pass' => 0,
            'pass_remark' => '',
            'pass_type'=>''
        ];
        $isPass = $this->checkRule($rowData);
        $rowData['is_pass'] = $isPass ? 1 : 0;
        $rowData['pass_remark'] = $this->forbidMsg;
        $rowData['pass_type'] = $this->forbidType;
        if (!$isPass) {
            $this->toolServer->error($this->forbidMsg);
        } else {
            // 广告位获取
            $ads = $this->getAds($rowData['producer']);
            // 策略获取
            $tactics = $this->getTactics();
            $appid = $this->linkRow['appid'];
            $rowData['appid'] = $appid;
            $data = [
                'appid'=>$appid,
                'tactics'=>$tactics,
                'ads'=>$ads,
                'limit'=>$this->limitValue
            ];

            $this->redisServer->RPUSH($this->hapLogKey,json_encode($rowData));
            $this->toolServer->success('success',$data);
        }

    }

    /**
     * 检验屏蔽规则
     * @param $chanurlno
     * @return void
     */
    public function checkRule($rowData)
    {
        $now = $this->now;
        $this->forbidMsg = '';
        $isPass = true;
        // 签名验证
        if (!empty($rowData['oaid']) && !in_array($rowData['oaid'], $this->whiteOaids)) {
            $res = $this->toolServer->checkSign();
            if ($res !== true) {
                $this->setForbid(1, '签名错误');
                return false;
            }
        }

        // oaid黑名单判断
        if (!empty($rowData['oaid'])) {
            // 不做限制的oaid
            if (in_array($rowData['oaid'], $this->passOaid)) {
                return true;
            }
            // oaid黑名单限制
            if (!in_array($rowData['oaid'], $this->whiteOaids)) {
                $isExists = $this->redisServer->HEXISTS($this->blackOaidRedisTable, $rowData['oaid']);
                if ($isExists) {
                    $this->setForbid(2, 'oaid黑名单');
                    return false;
                }
            }
        }
        // ip黑名单判断
        if (!empty($rowData['ip'])) {
            if (!in_array($rowData['ip'], $this->whiteIps)) {
                $isExists = $this->redisServer->HEXISTS($this->blackIpRedisTable, $rowData['ip']);
                if ($isExists) {
                    $this->setForbid(3, 'IP黑名单');
                    return false;
                }
            }
        }
        // 投放链接数据
        $linkRow = $this->searchServer->getLinkRow($rowData['chanurlno']);
        if (empty($linkRow)) {
            $this->setForbid(4, 'invalid channel');
            return false;
        }
        $this->linkRow = $linkRow;
        if (!empty($linkRow['limit_rate'])) {
            $this->limitValue = $linkRow['limit_rate'];
        }
        if (empty($linkRow['ad_set']) || empty(json_decode($linkRow['ad_set'], true))) {
            $this->setForbid(11, 'no ads');
            return false;
        }
        // 屏蔽规则数据
        $ruleRow = $this->searchServer->getRuleRow($linkRow['channel_no'], $linkRow['appid'], $rowData['producer']);
        if (empty($ruleRow)) {
            $this->setForbid(5, 'no rule');
            return false;
        }
        $this->ruleRow = $ruleRow;

        // 来源应用检验
        if ($ruleRow['is_from_app'] == 1) {
            $fromPkg = explode(',', $ruleRow['from_app']);
            $extraApp = explode(',', $ruleRow['extra_app']);
            if (!empty($fromPkg)) {
                if (in_array($rowData['fromPkg'], $fromPkg)) {
                    $this->setForbid(6, '不在来源范围内');
                    return false;
                }
            } elseif (!empty($extraApp) && in_array($rowData['fromPkg'], $extraApp)) {
                $this->setForbid(6, '不在来源范围内');
                return false;
            }
        }
        // 检验时间戳
        if ($ruleRow['is_ts'] == 2) {
            $hapTs = (int)($rowData['hap_ts'] ?? 0);
            if (strlen('' . $hapTs) == 13) {
                $hapTs = (int)($hapTs / 1000);
            }
//            if ($now - $hapTs > 20 || $now < $hapTs) {
//                $this->setForbid(7,'时间戳超时');
//                return false;
//            }
        }

        // 检验ip
        if ($ruleRow['is_ip'] == 2 && $rowData['hap_ip'] != '127.0.0.1') {
            $hapIp = $rowData['hap_ip'] ?? 'xxxx';
            if ($hapIp == '__IPV4__') {
                $hapIp = $hap['_i'] ?? '';
                if (!empty($hapIp)) {
                    $hapIp = long2ip($hapIp);
                } else {
                    $hapIp = 'zdgvfasdv';
                }
            }
            $hapIp = str_replace("_", "", $hapIp);
            if ($rowData['ip'] !== $hapIp) {
                $this->setForbid(8, 'ip错误');
                return false;
            }
        }
        // 检验oaid
        if ($ruleRow['is_oaid'] == 2) {
            $hapOaid = $rowData['hap_oaid'] ?? 'sdgfsa';
            if ($hapOaid == '__OAID__') {
                $hapOaid = 'sdgfsa';
            }
            if ($rowData['oaid'] !== $hapOaid) {
                $this->setForbid(9, 'oaid不匹配');
                return false;
            }
        }

        // 检验地区
        if ($ruleRow['is_address'] == 1) {
            if (!empty($ruleRow['city'])) {
                $cityArr = explode(',', $ruleRow['city']);
                $ipArr = explode('.', $rowData['ip']);
                $clientIp = $ipArr[0] . '.' . $ipArr[1] . '.' . $ipArr[2];
                $redisAddress = $this->redisServer->hget('ipAddress', $clientIp);
                if (!empty($redisAddress)) {
                    $this->address = $redisAddress;
                    $areaArr = explode('|', $redisAddress);
                    $clientCity = $areaArr[3];
                    if (in_array($clientCity, $cityArr)) {
                        $this->setForbid(10, '该地区不在范围内');
                        return false;
                    }
                } else {
                    include_once "../server/XkRegion.php";
                    $regionServer = new  XkRegion();
                    $redisAddress = $regionServer->memorySearch($rowData['ip']);
                    $areaArr = explode('|', $redisAddress['region']);
                    if (isset($areaArr[3])) {
                        $this->address = $redisAddress;
                        $clientCity = $areaArr[3];
                        if (in_array($clientCity, $cityArr)) {
                            $this->setForbid(10, '该地区不在范围内');
                            return false;
                        }
                    } else {
                        // 请求获取ip地址
                    }

                }
            }
        }
        return true;
    }

    /**
     * 设置屏蔽结果
     * @param $type
     * @param $msg
     * @return void
     */
    public function setForbid($type, $msg)
    {
        $this->forbidType = $type;
        $this->forbidMsg = $msg;
    }


    public function getTactics()
    {
        $rule = $this->ruleRow;
        // 屏蔽策略
        $forbidTactics = json_decode($rule['content'], true);
        $adTactics = json_decode($rule['ad_tactics'], true);
        return [
            'forbid_tactics'=>$forbidTactics,
            'ad_tactics'=>$adTactics
        ];
    }

    /**
     * 获取广告位
     * @return array[]
     */
    public function getAds($producer): array
    {
        $linkRow = $this->linkRow;
        $adSet = json_decode($linkRow['ad_set'], true);
        $adList = $adSet[$producer] ?? [];
        if (empty($adList)) {
            return ['need' => [], 'no_need' => []];
        }
        $placeIds = array_column($adList, 'place_id');
        $idsArr = $this->redisServer->hmget($this->placeKey.':' . date('Ymd', time()), $placeIds);
        $needArr = $noNeedArr = [];
        foreach ($adList as $adRow) {
            $adRow['rate'] = empty($idsArr[$adRow['place_id']]['rate']) ? 0 : $idsArr[$adRow['place_id']]['rate'];
//            $adRow['rate'] = mt_rand(0,100);
            if ($adRow['rate'] > $this->limitValue) {
                $needArr[] = $adRow;
            } else {
                if ($adRow['platform'] == 'agd') {
                    // 因为第一个广告位要求是agd的，所以给个最高单价方便排序
                    $adRow['price'] = 999999999;
                }
                $noNeedArr[] = $adRow;
            }
        }
        // 不需要补量的按照单价排序，需要补量的按照点击率排序
        usort($needArr, function ($a, $b) {
            return strcmp($b['rate'], $a['rate']);
        });

        // 如果需要补量的广告位超过两个，需要从末尾回填到不需要补量的数组里去
        $needCount = count($needArr);;
        if ($needCount > 2) {
            for ($i = 2; $i < $needCount; $i++) {
                $noNeedArr[] = $needArr[$i];
                unset($needArr[$i]);
            }
        }
        usort($noNeedArr, function ($a, $b) {
            return strcmp($b['price'], $a['price']);
        });
        return ['need' => $needArr, 'no_need' => $noNeedArr];


    }
}

$wap = new index();
$wap->exc();
